package com.huan.es8.nullvalue;

import co.elastic.clients.elasticsearch._types.mapping.IntegerNumberProperty;
import co.elastic.clients.elasticsearch._types.mapping.KeywordProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.huan.es8.AbstractEs8Api;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

import java.io.IOException;
import java.util.Arrays;

/**
 * 使用 null_value 来处理null值
 *
 * @author huan.fu
 * @date 2023/1/29 - 12:28
 */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class NullValueApi extends AbstractEs8Api {

    public static final String INDEX_NAME = "index_null_value";

    // @BeforeAll
    public void createIndex() throws IOException {
        client.indices()
                .create(indexRequest ->
                        indexRequest.index(INDEX_NAME)
                                .mappings(mappings ->
                                        // 1. null_value 只影响数据的索引方式，它不会修改 _source 文档
                                        // 2. 一个空数组[]不包含明确的 null，因此不会被 null_value 替换。
                                        // 3. null_value 需要和 字段的 类型值 保持一致
                                        mappings.properties("name", new Property(new KeywordProperty.Builder().nullValue("--").build()))
                                                .properties("address", new Property(new TextProperty.Builder().build()))
                                                .properties("age", new Property(new IntegerNumberProperty.Builder().nullValue(-1).build()))
                                )
                );
        bulk(INDEX_NAME, Arrays.asList(
                "{\"name\":null,\"age\":10}",
                "{\"name\":\"张三\"}",
                "{\"name\":\"张三\",\"age\":null}",
                // 这个使用 -- 无法查询出来，需要使用 bool -> must_not -> exists 来查询 一个空数组不包含明确的 null，因此不会被 null_value 替换
                "{\"name\":[],\"age\":20}",
                "{\"name\":[null],\"age\":60}",
                "{\"name\":[null,\"123\"],\"age\":70}",
                "{\"name\":[\"123\",null],\"age\":80}"
        ));
    }

    @Test
    @DisplayName("查询null值")
    public void test01() throws IOException {
        SearchRequest request = SearchRequest.of(searchRequest ->
                searchRequest.index(INDEX_NAME)
                        .query(query ->
                                // 此处需要使用 -- 来查询，因为在mapping设置的时候，null值使用的是 --，但是在 _source 中，还是原始的值，不会是null值
                                query.term(term -> term.field("name").value("--"))
                        )
                        .size(100)
        );

        System.out.println("request: " + request);
        SearchResponse<Object> response = client.search(request, Object.class);
        System.out.println("response: " + response);
    }

    @Test
    @DisplayName("通过 bool->must_not->exists来 查询null值， 可以查询字段的值为 null，或者空数组")
    public void test02() throws IOException {
        SearchRequest request = SearchRequest.of(searchRequest ->
                searchRequest.index(INDEX_NAME)
                        .query(query ->
                                // 可以查询出来 name=[] 或 name=null 的值，并且不受数据类型的限制
                                query.bool(bool -> bool.mustNot(mustNot -> mustNot.exists(exists -> exists.field("name"))))
                        )
                        .size(100)
        );

        System.out.println("request: " + request);
        SearchResponse<Object> response = client.search(request, Object.class);
        System.out.println("response: " + response);
    }

    // @AfterAll
    public void deleteIndex() throws IOException {
        deleteIndex(INDEX_NAME);
    }

}
